package com.kyubi.learner;

import java.util.Vector;

import com.kyubi.common.config.ConfigKeys;
import com.kyubi.common.config.Configuration;

import weka.core.Instance;
import weka.core.Instances;
import weka.core.neighboursearch.LinearNNSearch;

/**
 * @deprecated
 * @author anand
 *
 */
public class PerceptronLearner {

	private Vector<Instances> classifierInstances = null;
	private Vector<LinearNNSearch> classifiers = null;
	private double[] weights = null;
	private double lRate;
	private long testSize;
	
	// stats
	private long error = 0;

	public PerceptronLearner(Vector<Instances> classifierInstances, double lRate) {
		this.classifierInstances = classifierInstances;
		this.classifiers = new Vector<LinearNNSearch>();
		this.weights = new double[classifierInstances.size()];
		this.lRate = lRate;
		this.testSize = this.classifierInstances.firstElement().numInstances();

		for (int i = 0; i < this.classifierInstances.size(); i++) {
			LinearNNSearch classifier = new LinearNNSearch(
					this.classifierInstances.elementAt(i));
			classifiers.add(classifier);
		}
	}

	public void runForEpochs(int epochs) {
		for (int i = 0; i < epochs; i++) {
			runEpoch();
		}
	}

	private void runEpoch() {
		this.error = 0;
		for (int i = 0; i < testSize; i++) {
			run(i);
		}
		System.out.println("Accracy: " + (testSize-error)*100/testSize);
	}

	private void run(int index) {
		Vector<Double> predictions = new Vector<Double>();
		double actual = 0;
		Instance instance = null;

		// accumulate predictions
		for (int i = 0; i < this.classifiers.size(); i++) {
			LinearNNSearch classifier = this.classifiers.get(i);
			try {
				instance = this.classifierInstances.get(i).instance(index);
				Instance neighbor = classifier.nearestNeighbour(instance);
				predictions.add(neighbor.value(neighbor.numAttributes() - 1));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		actual = instance.value(instance.numAttributes()-1);
		
		// compute prediction
		double predicted = 0;
		for(int i=0; i<predictions.size(); i++) {
			predicted += (this.weights[i] * predictions.get(i));
		}
		
		// update weights
		if((actual == 1) && (predicted < 1) || (actual == 0) && (predicted >= 1)) {
			for(int i=0; i<this.weights.length; i++) {
				this.weights[i] += (lRate*(actual-predicted));
			}
			
			this.error++;
		}
	}

	public static void main(String[] args) {
		try {
			Configuration c = Configuration
					.getSingleton("/Users/anand/kyubi/config/kyubi_java.ini");

			Vector<Instances> insts = new Vector<Instances>();
			for (int i = 0; i < 3; i++) {
				insts.add(c.readARFF("/Users/anand/kyubi/tmp/file_" + i
						+ ".arff"));
			}

			PerceptronLearner pl = new PerceptronLearner(insts, 0.1);
			pl.runForEpochs(500);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
